package com.yz.smartpos.yztester.apifuntest.tests;

import android.util.Log;

import com.yz.smartpos.yzsmartposapi.modules.serialPort.YZSerilPortListener;
import com.yz.smartpos.yzsmartposapi.utils.GPMethods;
import com.yz.smartpos.yztester.apifuntest.annotation.TCAction;
import com.yz.smartpos.yztester.apifuntest.annotation.TCMode;
import com.yz.smartpos.yztester.apifuntest.annotation.TCPrecondition;
import com.yz.smartpos.yztester.apifuntest.annotation.TCResult;
import com.yz.smartpos.yztester.apifuntest.annotation.TCSummary;
import com.yz.smartpos.yztester.util.ApiTestCase;
import com.yz.smartpos.yztester.util.TestCase;
import com.yz.smartpos.yztester.util.Utils;

import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

/**
 *
 */
@RunWith(JUnit4.class)
public class SerialPortTest extends ApiTestCase {
    private static String TAG = "SerialPortTest";
    private static String Module = "SerialPortTest";

    public static List<TestCase> testcaseList = Arrays.asList(
            new TestCase("RunAllAuto"),
            new TestCase("RunAllAutoNotRun"),
            new TestCase("RunAllAutoFail"),
            new TestCase(0, 3, Module, "SerilPort_open_fun1", TestCase.MANUAL),
            new TestCase(0, 4, Module, "SerilPort_close_fun1", TestCase.MANUAL),
            new TestCase(0, 5, Module, "SerilPort_send_fun1", TestCase.MANUAL),
            new TestCase(0, 6, Module, "SerilPort_recv_fun1", TestCase.MANUAL),
            new TestCase(0, 7, Module, "SerilPort_openClose_fun1", TestCase.MANUAL),
            new TestCase(0, 8, Module, "SerilPort_openClose_fun2", TestCase.MANUAL),
            new TestCase(0, 9, Module, "SerilPort_fun1", TestCase.AUTO),
            new TestCase(0, 10, Module, "SerilPort_fun2", TestCase.AUTO),
            new TestCase(0, 11, Module, "SerilPort_per1", TestCase.MANUAL),
            new TestCase(0, 12, Module, "SerilPort_per11", TestCase.MANUAL),
            new TestCase(0, 13, Module, "SerilPort_per2", TestCase.MANUAL)
    );
    private long startTime;
    private long runTime;
    private static Calendar c1;
    static Random rand = new Random();

    int g_flag = 0;
    long g_recvLen = 0;

    @Override
    public void setUp() throws Exception {
    }

    @After
    @Override
    public void tearDown() throws Exception {
        super.tearDown();
    }

    static int g_count = 0;
    static byte[] g_recvData = null;
    static long g_recvTotalLen = 0;

    static class MyYZSerilPortListener implements YZSerilPortListener {
        @Override
        public void onReceiveSerilPortData(byte[] data) {
            g_count++;
            if (g_recvData == null)
                g_recvData = data;
            else if(data.length + g_recvTotalLen <= g_recvData.length){
                System.arraycopy(data,0, g_recvData, (int)g_recvTotalLen, data.length);
            }
            g_recvTotalLen = g_recvTotalLen + data.length;
            Log.i(TAG, String.format("%d receive dataLen = %d, totalLen = %d", g_count, data.length, g_recvTotalLen));
            Log.i(TAG, String.format("%d receive data = %s", g_count, GPMethods.bytesToHexString(data)));
        }
    }

    @Test
    @TCSummary("打开端口")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_open_fun1() {
        try{
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("释放端口")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_close_fun1() {
        try{
            boolean reb = smartPosApi.releaseSerialPort();
            assertTrue("releaseSerialPort reb:" + reb, reb == true);
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("发送数据")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_send_fun1() {
        try{
            String sendData = "This is a test!";

            Logger.appendLog_inner("sendSerilPortData start");
            smartPosApi.sendSerilPortData(sendData.getBytes());
            Logger.appendLog_inner("sendSerilPortData end, len=" + sendData.length());
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }


    @Test
    @TCSummary("接收数据")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_recv_fun1() {
        try{
            g_recvTotalLen = 0;
            g_recvData = null;
            smartPosApi.setSerilPortListener(new MyYZSerilPortListener());
            int i = 0;
            Logger.stop_flag = 0;
            while(true){
                if(Logger.stop_flag == 1) {Logger.appendLog("stop by manual");break;}
                if(g_recvData != null) {
//                    Logger.appendLog(String.format("recvData %d, totalLen %d", g_recvData.length, g_recvTotalLen));
                    Logger.appendLog(String.format("recvData %d:%s", g_recvData.length, GPMethods.bytesToHexString(g_recvData)));
                    g_recvData = null;
                    i++;
                }
            }
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("重复打开端口、发送数据、关闭端口")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_openClose_fun1() {
        try{
            int test_cnt = 10;
            String sendData = "This is a test!\r\n";
            smartPosApi.releaseSerialPort();

            for(int i = 0; i < test_cnt; i++) {
                Logger.appendLog("test cnt = " + i);
                boolean reb = smartPosApi.openSerialPort();
                assertTrue("openSerialPort reb:" + reb, reb == true);
                if (reb == false) return;

                try {
                    Logger.appendLog_inner(String.format("start send, sendLen=%d", sendData.length()));
                    Log.i(TAG, String.format("start send, sendLen=%d", sendData.length()));
                    smartPosApi.sendSerilPortData(sendData.getBytes());
                    Logger.appendLog_inner(String.format("send ok"));
                }catch (Exception  e){
                    Utils.printException(e);
                }
                Log.i(TAG, String.format("send ok"));

                smartPosApi.releaseSerialPort();
            }
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("重复打开端口、发送数据、接收数据、关闭端口(短链接测试)")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_openClose_fun2() {
        try{
            int test_cnt = 10;
            String tmp = new String("This is a test!\r\n");
            byte[] sendData = tmp.getBytes(tmp);
            smartPosApi.releaseSerialPort();
            g_recvTotalLen = 0;
            g_count = 0;

            for(int i = 0; i < test_cnt; i++) {
                Logger.appendLog("test cnt = " + i);
                boolean reb = smartPosApi.openSerialPort();
                assertTrue("openSerialPort reb:" + reb, reb == true);
                if (reb == false) return;

                smartPosApi.setSerilPortListener(new MyYZSerilPortListener());

                try {
                    g_recvData = null;
                    Logger.appendLog_inner(String.format("start send, sendLen=%d", sendData.length));
                    Log.i(TAG, String.format("start send, sendLen=%d", sendData.length));
                    smartPosApi.sendSerilPortData(sendData);
                    Logger.appendLog_inner(String.format("send ok"));

                    Logger.stop_flag = 0;
                    while(true){
                        if(Logger.stop_flag == 1) {Logger.appendLog("stop by manual");break;}
                        if(g_recvData != null){
                            Logger.appendLog(String.format("recv %d", g_recvData.length));
                            assertTrue(String.format("%d cmp ok", i), Arrays.equals(g_recvData, sendData));
                            break;
                        }
                    }
                }catch (Exception  e){
                    Utils.printException(e);
                }
                Log.i(TAG, String.format("send ok"));

                smartPosApi.releaseSerialPort();
            }
        }catch (Exception  e) {
            Utils.printException(e);
        }
    }
    @Test
    @TCSummary("发送接收数据100次，每次发送1024字节(长连接测试)")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("AUTO")
    public void SerilPort_fun1() {
        try {
            int test_cnt = 100;
            smartPosApi.releaseSerialPort();
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
            if (reb == false) return;

            g_count = 0;
            smartPosApi.setSerilPortListener(new MyYZSerilPortListener());

            for(int i = 1; i <= test_cnt; i++) {
                byte[] sendData = new byte[1024];
                byte[] tmpByte = new byte[1];
                rand.nextBytes(tmpByte);
                Arrays.fill(sendData, tmpByte[0]);

                g_recvTotalLen = 0;
                g_recvData = new byte[sendData.length];
                Arrays.fill(g_recvData, (byte)0);
                smartPosApi.sendSerilPortData(sendData);
                Logger.appendLog(String.format("%d send %d ok", i, sendData.length));

                Logger.stop_flag = 0;
                while(true){
                    if(Logger.stop_flag == 1) {Logger.appendLog("stop by manual");break;}
                    if(g_recvTotalLen == sendData.length) {
                        Logger.appendLog(String.format("recv %d", g_recvTotalLen));
                        assertTrue(String.format("%d cmp ok", i), Arrays.equals(g_recvData, sendData));
                        break;
                    }
                }
            }
            smartPosApi.releaseSerialPort();
        } catch (Exception e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("发送接收数据100次，每次发送1~100字节")
    @TCPrecondition("")
    @TCAction("")
    @TCResult("")
    @TCMode("AUTO")
    public void SerilPort_fun2() {
        try {
            int sendLen = 1;
            int test_cnt = 100;
            smartPosApi.releaseSerialPort();
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
            if (reb == false) return;

            g_recvTotalLen = 0;
            smartPosApi.setSerilPortListener(new MyYZSerilPortListener());

            for(int i = 1; i <= test_cnt; i++) {
                byte[] sendData = new byte[i];
                byte[] tmpByte = new byte[1];
                rand.nextBytes(tmpByte);
                Arrays.fill(sendData, tmpByte[0]);

                g_recvData = null;
                smartPosApi.sendSerilPortData(sendData);
                Logger.appendLog(String.format("%d send %d ok", i, sendData.length));

                Logger.stop_flag = 0;
                while(true) {
                    if(Logger.stop_flag == 1) {Logger.appendLog("stop by manual");break;}
                    if(g_recvData != null) {
                        Logger.appendLog(String.format("recv %d", g_recvData.length));
                        assertTrue(String.format("%d cmp ok", i), Arrays.equals(g_recvData, sendData));
                        break;
                    }
                }
            }
            smartPosApi.releaseSerialPort();
        } catch (Exception e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("通讯速率(上行速率)")
    @TCPrecondition("")
    @TCAction("一次性发送100M数据，PC端使用sscom接收数据，掐表计时")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_per1() {
        try {
            int test_cnt = 100;

            InputStream in =  assetManager.open("fonts/GB18030.ttf");
            int lenght = in.available();
            byte[] buffer = new byte[lenght];
            in.read(buffer);

            smartPosApi.releaseSerialPort();
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
            if (reb == false) return;

            g_recvLen = 0;

            long sendLen_total = 0;
            Logger.appendLog_inner(String.format("start send, sendLen=%d", lenght));
            for(int i = 0; i < lenght/(5*1024); i ++) {
                int sendLen = 5*1024;
                if(i == lenght/(5*1024) - 1) {
                    sendLen = lenght - (5*1024)*i;
                }
                byte[] sendData = new byte[sendLen];

                System.arraycopy(buffer, i * (5*1024), sendData, 0, sendData.length);
                smartPosApi.sendSerilPortData(sendData);
                sendLen_total = sendLen_total + sendLen;
                Logger.appendLog(String.format("%d send %d ok, total send %d", i, sendData.length, sendLen_total));
                Log.i(TAG, String.format("%d send %d ok", i, sendData.length));
            }
            Logger.appendLog_inner(String.format("send ok, sendLen_total=%d", sendLen_total));

            smartPosApi.releaseSerialPort();
        } catch (Exception e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("通讯速率(上行速率)")
    @TCPrecondition("")
    @TCAction("一次性发送100M数据，PC端使用sscom接收数据，掐表计时")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_per11() {
        try{
            int test_cnt = 100;

            InputStream in =  assetManager.open("fonts/GB18030.ttf");
            int lenght = in.available();
            byte[] buffer = new byte[lenght];
            in.read(buffer);

            smartPosApi.releaseSerialPort();
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
            if (reb == false) return;

            g_recvLen = 0;

            Logger.appendLog_inner(String.format("start send, sendLen=%d", lenght));
            Log.i(TAG, String.format("start send, sendLen=%d", lenght));
            smartPosApi.sendSerilPortData(buffer);
            Logger.appendLog_inner(String.format("send ok"));
            Log.i(TAG, String.format("send ok"));

            smartPosApi.releaseSerialPort();
        }catch (IOException  e) {
            Utils.printException(e);
        }
    }

    @Test
    @TCSummary("通讯速率(下行速率，PC发数据给终端)")
    @TCPrecondition("")
    @TCAction("PC端使用sscom接收数据发送大于100M的文件，计算终端从开始接收到结束的时间")
    @TCResult("")
    @TCMode("MANUAL")
    public void SerilPort_per2() {
        try {
            InputStream in =  assetManager.open("fonts/GB18030.ttf");
            int lenght = in.available();
            int flag = 0;

            smartPosApi.releaseSerialPort();
            boolean reb = smartPosApi.openSerialPort();
            assertTrue("openSerialPort reb:" + reb, reb == true);
            if (reb == false) return;

            g_recvTotalLen = 0;
            g_recvData = new byte[lenght];
            smartPosApi.setSerilPortListener(new MyYZSerilPortListener());
            Logger.stop_flag = 0;
            while(true){
                if(Logger.stop_flag == 1) {Logger.appendLog("stop by manual");break;}
                if(flag == 0 && g_recvTotalLen != 0){
                    c1 = Calendar.getInstance();
                    flag = 1;
                }
                if(g_recvTotalLen >= lenght ) {
                    long time = Calendar.getInstance().getTimeInMillis() - c1.getTimeInMillis();
                    float speed = lenght/time*1000/1024;
                    Logger.appendLog_inner(String.format("recv end, recv time = %d s, recv len = %d, speed = %d KB/s", time/1000, g_recvLen, speed));
                    break;
                }
            }
            smartPosApi.releaseSerialPort();
        } catch (Exception e) {
            Utils.printException(e);
        }
    }
}
